package algorithm;

import pojo.TaskAssignment;
import utils.WorkCalendar;
import pojo.WorkerHandle;
import utils.DateHandle;

import java.sql.SQLOutput;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * 以交期和工人难度匹配为主要考虑因素
 */
public class SimulatedAnneling {
    //模拟退火参数
    private double INITIAL_TEMPERATURE = 2000.0;   // 初始温度
    private double COOLING_RATE = 0.98;            // 冷却率
    private int MAX_ITERATIONS_PER_TEMP = 2000;    // 每温度下最大迭代次数
    private double MIN_TEMPERATURE = 10;           // 最低温度
    private int NO_IMPROVEMENT_LIMIT = 30;        // 无改进次数限制
    private int REHEAT_THRESHOLD = 50;             // 重加热阈值
    private double m=0.3185;
    private double alpha=-0.4815;

    private List<WorkerHandle> workers;                  // 工人列表
    private int year;                              // 年份
    private int month;// 月份
    private List<TaskAssignment> tasks;
    private Random rand = new Random();            // 随机数生成器
    private LocalDate baseDate;                     //基准日期
    private WorkCalendar workCalendar;

    /**
     * 构造函数
     * @param tasks  需要加工的任务
     * @param month
     * @param year
     * @param workers
     */
    public SimulatedAnneling(List<TaskAssignment> tasks, int month, int year, List<WorkerHandle> workers) {
        this.tasks = tasks;
        this.month = month;
        this.year = year;
        this.workers = workers;
        this.workCalendar = new WorkCalendar();
        this.baseDate = LocalDate.of(year, month, 1);
    }

    /**
     * 单件的时间公式随着加工件数的变化情况
     * 每重新开始一个任务repetition归零
     * @param baseTime 基准时间
     * @param alpha 影响因子
     * @param m 效率下限
     * @param repetition 重复次数
     * @return 加工所需的时间
     */
    public  static double   predictTime(double baseTime, double alpha, double m, int repetition) {
    //  单件的时间公式随着加工件数的变化情况
    //  每重新开始一个任务repetition归零
        double learningTerm = m + (1 - m) * Math.pow(repetition, alpha);
        return learningTerm * baseTime;
    }

    private static final int CACHE_MAX_SIZE = 1000; // 缓存最大容量

    // 使用LinkedHashMap实现简单的LRU缓存
    private Map<String, Integer> assignedQuantityCache = new LinkedHashMap<String, Integer>(CACHE_MAX_SIZE + 1, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
            return size() > CACHE_MAX_SIZE;
        }
    };
    // 优化缓存清理机制
    public void clearCacheForTask(TaskAssignment task) {
        String taskKey = task.getItemID() + "_" + task.getOrderCode();
        assignedQuantityCache.remove(taskKey);
    }

    // 在任务分配完成后调用此方法刷新缓存
    public void refreshCache() {
        assignedQuantityCache.clear();

        // 重新填充缓存
        Map<String, Integer> tempCache = new HashMap<>();
        for (WorkerHandle worker : workers) {
            for (TaskAssignment assignment : worker.getAssignments()) {
                String taskKey = assignment.getItemID() + "_" + assignment.getOrderCode();
                int currentQuantity = tempCache.getOrDefault(taskKey, 0);
                tempCache.put(taskKey, currentQuantity + assignment.getAssignedQuantity());
            }
        }

        assignedQuantityCache.putAll(tempCache);
    }

    /**
     * 计算已经分配的任务数量，使用缓存提高性能
     */
    private int calculateAlreadyAssignedQuantity(TaskAssignment task) {
        String taskKey = task.getItemID() + "_" + task.getOrderCode();

        // 如果缓存中有值，直接返回
        if (assignedQuantityCache.containsKey(taskKey)) {
            return assignedQuantityCache.get(taskKey);
        }

        int totalAssignedQuantity = 0;
        for(WorkerHandle worker: workers) {
            for(TaskAssignment assignment: worker.getAssignments()){
                if(assignment.getItemID().equals(task.getItemID()) &&
                        assignment.getOrderCode().equals(task.getOrderCode())){
                    totalAssignedQuantity += assignment.getAssignedQuantity();
                }
            }
        }

        // 存入缓存
        assignedQuantityCache.put(taskKey, totalAssignedQuantity);
        return totalAssignedQuantity;
    }

    /**
     * 当分配任务后，需要更新缓存
     */
    private void updateAssignedQuantityCache(TaskAssignment task, int quantity) {
        String taskKey = task.getItemID() + "_" + task.getOrderCode();
        int currentQuantity = assignedQuantityCache.getOrDefault(taskKey, 0);
        assignedQuantityCache.put(taskKey, currentQuantity + quantity);
    }
    /**
     * 使用改进的二分查找找到在给定时间内可以完成的最大数量
     * 通过缓存中间结果提高效率
     * @param baseTime 基准时间
     * @param alpha 影响因子
     * @param m 效率下限
     * @param availableTime 可用时间
     * @param maxQuantity 最大可分配数量
     * @return 可分配的最大数量
     */
    private int findMaxAssignableQuantity(double baseTime, double alpha, double m,
                                          double availableTime, int maxQuantity, TaskAssignment task) {
        if (maxQuantity <= 0 || availableTime <= 0) {
            return 0;
        }

        // 先扣除准备时间
        double availableTimeAfterPrep = availableTime - task.getPreCycle();
        if (availableTimeAfterPrep <= 0) {
            return 0; // 没有足够时间完成准备工作
        }

        int left = 0;
        int right = maxQuantity;
        int result = 0;

        // 扩大预计算数组大小以处理更多数量
        int precomputeSize = Math.min(maxQuantity + 1, 500);
        double[] unitTimes = new double[precomputeSize];
        for (int i = 0; i < unitTimes.length; i++) {
            unitTimes[i] = predictTime(baseTime, alpha, m, i + 1);
        }

        // 正确计算累积时间
        double[] cumulativeTimes = new double[unitTimes.length];
        cumulativeTimes[0] = unitTimes[0];
        for (int i = 1; i < unitTimes.length; i++) {
            cumulativeTimes[i] = cumulativeTimes[i-1] + unitTimes[i];
        }

        while (left <= right) {
            int mid = left + (right - left) / 2;
            double totalTime = 0;
            if (mid > 0) {
                if (mid <= unitTimes.length) {
                    // 使用预计算的累积时间
                    totalTime = cumulativeTimes[mid - 1];
                } else {
                    // 对于超出预计算范围的数量，从已知的最大累积时间开始
                    totalTime = cumulativeTimes[unitTimes.length - 1];

                    // 然后计算剩余部分
                    for (int i = unitTimes.length; i < mid; i++) {
                        totalTime += predictTime(baseTime, alpha, m, i + 1);
                    }
                }
            }

            // 这里不需要再加准备时间，因为我们已经提前减去了
            if (totalTime <= availableTimeAfterPrep) {
                result = mid;
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }

        return result;
    }
    /**
     * 计算可分配数量
     * 采用了工人对于零件的熟练度proficiency以及学习曲线效应
     * 熟练度先默认返回1，以后可以根据需求进行扩展
     * @param task
     * @param availableTime
     * @return
     */
    public int calculateAssignableQuantity(TaskAssignment task, double availableTime) {
        if (availableTime <= 0) {
            return 0;
        }

        double baseTime = task.getMakeCycle();
        int alreadyAssignedQuantity = calculateAlreadyAssignedQuantity(task);
        int remainQuantity = task.getAssignedQuantity() - alreadyAssignedQuantity;

        // 如果没有剩余数量，直接返回0
        if (remainQuantity <= 0) {
            return 0;
        }

        // 使用修改后的二分查找函数，传递task以获取准备时间
        int maxAssignable = findMaxAssignableQuantity(baseTime, alpha, m, availableTime, remainQuantity, task);

        System.out.println("计算任务 " + task.getItemID() + "_" + task.getOrderCode() +
                " 可分配数量: " + maxAssignable +
                " (剩余: " + remainQuantity +
                ", 可用时间: " + availableTime +
                ", 准备时间: " + task.getPreCycle() + ")");

        return maxAssignable;
    }

    /**
     * 为工人分配任务
     * @param task
     * @param worker
     * @param quantity
     */
    public void allocateTask(TaskAssignment task, WorkerHandle worker, int quantity) {
        if (quantity <= 0) {
            return;
        }

        System.out.println("准备分配给工人 " + worker.getEmployeeName() +
                " 数量: " + quantity +
                ", 任务: " + task.getItemID() + "_" + task.getOrderCode());

        double baseTime = task.getMakeCycle();
        double preCycle = task.getPreCycle();

        // 计算总时间，考虑学习曲线效应
        double totalMakeTime = 0;
        for (int i = 1; i <= quantity; i++) {
            totalMakeTime += predictTime(baseTime, alpha, m, i);
        }
        double totalTime = preCycle + totalMakeTime;

        TaskAssignment taskAssignment = new TaskAssignment(
                task.getItemID(),
                task.getOrderCode(),
                task.getFlowOrderCode(),
                task.getItemName(),
                task.getItemDifficulty(),
                task.getWorkcenterName(),
                quantity,
                task.getPreCycle(),
                task.getMakeCycle(),
                task.getDeadline()
        );
        worker.assignTask(taskAssignment);
        worker.setAvailable(Math.max(worker.getAvailable() - totalTime, 0));

        // 使用增量更新而不是完全重新计算
        worker.incrementalScheduleUpdate(taskAssignment, baseDate);

        // 更新缓存
        updateAssignedQuantityCache(task, quantity);

        System.out.println("成功分配给工人 " + worker.getEmployeeName() +
                " 数量: " + quantity +
                ", 耗时: " + String.format("%.2f", totalTime) +
                ", 剩余可用时间: " + String.format("%.2f", worker.getAvailable()));
    }
    /**
     * 初始任务分配
     */
    private void printWorkerScores(String stage, TaskAssignment currentTask) {
        System.out.println("\n===== " + stage + " =====");

        for (WorkerHandle worker : workers) {
            double availableTime = worker.getAvailable();
            double score = 0;

            if (currentTask != null && worker.canHandle(currentTask)) {
                score = availableTime/worker.getEfficiencyCodfficient();
            }

            System.out.println(
                    "工人: " + worker.getEmployeeName() +
                            ", 可用时间: " + String.format("%.2f", availableTime) +
                            ", 效率系数: " + String.format("%.2f", worker.getEfficiencyCodfficient()) +
                            (currentTask != null ? ", 任务分数: " + String.format("%.2f", score) : "")
            );
        }
    }
    public void initialAssignment() {
        System.out.println("初始化");

        // 使用Map缓存每个任务的已分配数量，避免重复计算
        Map<String, Integer> taskAssignedQuantityMap = new HashMap<>();

        // 初始化记录未分配任务的列表
        List<TaskAssignment> unassignedTasks = new ArrayList<>();

        // 按照截至日期升序排序任务
        Collections.sort(tasks, Comparator.comparing(TaskAssignment::getDeadline));

        // 计算工人的可用时间
        double dailyAvailable = 8.0;
        double dayInMonth = 19;
        System.out.println("工作日数量: " + dayInMonth + " 天");

        // 初始化工人可用时间
        for (WorkerHandle worker : workers) {
            worker.setAvailable(worker.getEfficiencyCodfficient() * dailyAvailable * dayInMonth);
            worker.setWorkCalendar(workCalendar);
            System.out.println("工人 " + worker.getEmployeeName() +
                    " 初始可用时间: " + String.format("%.2f", worker.getAvailable()) +
                    " 小时, 效率系数: " + String.format("%.2f", worker.getEfficiencyCodfficient()));
        }

        // 打印工人初始状态分数
        printWorkerScores("初始状态", null);
        int totalTaskQuantity = 0;
        int totalAssignedQuantity = 0;

        // 分配任务
        for (TaskAssignment task : tasks) {
            totalTaskQuantity += task.getAssignedQuantity();
            System.out.println("\n准备分配任务: " + task.getItemID() + "_" + task.getOrderCode() +
                    ", 数量: " + task.getAssignedQuantity() +
                    ", 难度: " + task.getItemDifficulty() +
                    ", 截止日期: " + task.getDeadline());

            // 生成任务唯一标识符
            String taskKey = task.getItemID() + "_" + task.getOrderCode();

            // 从缓存获取已分配数量，如果不存在则计算并缓存
            int totalAlreadyAssigned = taskAssignedQuantityMap.getOrDefault(taskKey, 0);
            if (totalAlreadyAssigned == 0) {
                totalAlreadyAssigned = calculateAlreadyAssignedQuantity(task);
                taskAssignedQuantityMap.put(taskKey, totalAlreadyAssigned);
            }

            int remainQuantity = task.getAssignedQuantity() - totalAlreadyAssigned;
            if (remainQuantity <= 0) {
                System.out.println("任务 " + taskKey + " 已完全分配，跳过");
                continue; // 任务已完全分配，跳过
            }

            int initialRemainQuantity = remainQuantity;
            boolean progress = true;

            // 尝试分配任务，使用布尔标志替代复杂的数量比较
            int roundCount = 0;
            while (remainQuantity > 0 && progress) {
                roundCount++;
                System.out.println("\n分配回合 #" + roundCount + " - 剩余数量: " + remainQuantity);
                progress = false; // 假设本轮无法分配
                WorkerHandle bestWorker = null;
                double maxScore = Double.NEGATIVE_INFINITY;
                int maxAssignedQuantity = 0;

                // 贪心策略选择合适工人
                System.out.println("计算每位工人的分数:");
                for (WorkerHandle worker : workers) {
                    if (worker.canHandle(task)) {
                        // 使用当前可用时间
                        double availableTime = worker.getAvailable();
                        int assignment = calculateAssignableQuantity(task, availableTime);

                        // 计算分数 - 考虑可用时间和效率系数
                        double score = (availableTime > 0) ? availableTime : 0;

                        System.out.println("  - " + worker.getEmployeeName() +
                                ": 可用时间=" + String.format("%.2f", availableTime) +
                                ", 可分配数量=" + assignment +
                                ", 分数=" + String.format("%.2f", score));

                        if (score > maxScore && assignment > 0) {
                            maxScore = score;
                            bestWorker = worker;
                            maxAssignedQuantity = assignment;
                        }
                    } else {
                        System.out.println("  - " + worker.getEmployeeName() + ": 不能处理此任务");
                    }
                }

                if (bestWorker != null && maxAssignedQuantity > 0) {
                    int quantity = Math.min(maxAssignedQuantity, remainQuantity);

                    // 记录分配前的可用时间
                    double beforeAvailable = bestWorker.getAvailable();

                    // 分配任务
                    allocateTask(task, bestWorker, quantity);

                    // 记录分配后的可用时间
                    double afterAvailable = bestWorker.getAvailable();
                    double timeUsed = beforeAvailable - afterAvailable;

                    System.out.println("分配决策: 将 " + quantity + " 个零件分配给 " +
                            bestWorker.getEmployeeName() +
                            ", 耗时 " + String.format("%.2f", timeUsed) +
                            " 小时, 剩余可用时间: " + String.format("%.2f", afterAvailable));

                    // 更新缓存和剩余数量
                    totalAlreadyAssigned += quantity;
                    taskAssignedQuantityMap.put(taskKey, totalAlreadyAssigned);
                    remainQuantity -= quantity;
                    totalAssignedQuantity += quantity;
                    progress = true; // 本轮成功分配

                    // 打印每次分配后的工人分数
                    printWorkerScores("分配 " + quantity + " 个零件给 " + bestWorker.getEmployeeName() + " 后", task);
                } else {
                    System.out.println("无法找到合适的工人来分配任务");
                    break; // 无法继续分配
                }
            }

            // 如果还有剩余任务未分配，添加到未分配列表
            if (remainQuantity > 0) {
                TaskAssignment unassignedPart = new TaskAssignment(
                        task.getItemID(),
                        task.getOrderCode(),
                        task.getFlowOrderCode(),
                        task.getItemName(),
                        task.getItemDifficulty(),
                        task.getWorkcenterName(),
                        remainQuantity,
                        task.getPreCycle(),
                        task.getMakeCycle(),
                        task.getDeadline()
                );
                unassignedTasks.add(unassignedPart);
                System.out.println("警告: 无法分配 " + remainQuantity + " 个零件 " + taskKey);
            }

            // 记录分配情况
            int assignedAmount = initialRemainQuantity - remainQuantity;
            if (assignedAmount > 0) {
                System.out.println("总结: 成功分配 " + assignedAmount + " 个零件 " + taskKey);
            }
        }

        // 如果有未分配的任务，报告结果
        if (!unassignedTasks.isEmpty()) {
            System.out.println("\n警告: " + unassignedTasks.size() + " 个任务不能完全分配:");
            for (TaskAssignment task : unassignedTasks) {
                System.out.println("  - " + task.getItemID() + "_" + task.getOrderCode() +
                        ": " + task.getAssignedQuantity() + " 个零件");
            }
        }

        System.out.println("\n任务分配完成，最终分配结果:");
        int finalAssignedCount = 0;
        for (int i = 0; i < workers.size(); i++) {
            WorkerHandle worker = workers.get(i);
            System.out.println("\n工人: " + worker.getEmployeeName() +
                    ", 剩余可用时间: " + String.format("%.2f", worker.getAvailable()) + " 小时");
            List<TaskAssignment> taskAssignments = worker.getAssignments();
            if (taskAssignments.isEmpty()) {
                System.out.println("  没有分配任务");
            } else {
                for (int j = 0; j < taskAssignments.size(); j++) {
                    TaskAssignment t = taskAssignments.get(j);
//                    System.out.println("  任务 #" + (j+1) + ": " + t.getItemID() + "_" + t.getOrderCode() +
//                            ", 数量: " + t.getAssignedQuantity() +
//                            ", 难度: " + t.getItemDifficulty());
                    finalAssignedCount += t.getAssignedQuantity();
                }
            }
        }
        System.out.println("总需求零件数量：" + totalTaskQuantity);
        System.out.println("总分配零件数量：" + finalAssignedCount);
        if (totalTaskQuantity != finalAssignedCount) {
            System.out.println("警告: 总需求数量与总分配数量不匹配！差异: " + (totalTaskQuantity - finalAssignedCount));
        }
    }


    /**
     * 计算调度方案的成本
     * @param workers 工人列表
     * @return 成本值（越小越好）
     */
    private double calculateCost(List<WorkerHandle> workers) {
        double overduePenalty = 0.0;  // 超期惩罚因子
        double loadBalancePenalty = 0.0;  // 负载均衡惩罚因子

        // 超期惩罚权重
        final double OVERDUE_WEIGHT = 1000.0;
        // 负载均衡惩罚权重
        final double LOAD_BALANCE_WEIGHT = 100.0;

        // 增加任务分散惩罚
        final double TASK_FRAGMENTATION_WEIGHT = 30.0;
        double fragmentationPenalty = 0.0;

        // 检查每个工人的任务是否超期
        for (WorkerHandle worker : workers) {
            for (TaskAssignment task : worker.getAssignments()) {
                LocalDateTime endTime = task.getEndTime();
                if (endTime != null && endTime.toLocalDate().isAfter(task.getDeadline())) {
                    long daysLate = Duration.between(
                            task.getDeadline().atStartOfDay(),
                            endTime).toDays();
                    // 超期天数的惩罚是平方关系，使得超期越多惩罚越严重
                    overduePenalty += Math.pow(Math.max(0, daysLate), 2) * task.getAssignedQuantity();
                }
            }
        }

        // 计算工人负载均衡情况，考虑效率系数
        double[] normalizedLoads = new double[workers.size()];


        for (int i = 0; i < workers.size(); i++) {
            WorkerHandle worker = workers.get(i);
            double initialAvailable = worker.getEfficiencyCodfficient() * 8.0 * workCalendar.calculateWorkingDays(year, month);
            double usedTime = initialAvailable - worker.getAvailable();

            // 归一化负载，考虑效率系数
            double normalizedLoad = usedTime / (initialAvailable);
            normalizedLoads[i] = 1-normalizedLoad;
            loadBalancePenalty+= 1-normalizedLoad;
        }
        // 计算任务分散度
        Map<String, List<Integer>> taskDistribution = new HashMap<>();
        for (WorkerHandle worker : workers) {
            for (TaskAssignment task : worker.getAssignments()) {
                String taskKey = task.getItemID() + "_" + task.getOrderCode();
                if (!taskDistribution.containsKey(taskKey)) {
                    taskDistribution.put(taskKey, new ArrayList<>());
                }
                taskDistribution.get(taskKey).add(task.getAssignedQuantity());
            }
        }
        // 计算任务分散惩罚 - 分散的工人数越多，单个分配数量越小，惩罚越大
        for (Map.Entry<String, List<Integer>> entry : taskDistribution.entrySet()) {
            List<Integer> quantities = entry.getValue();
            // 如果一个任务被分给多个工人且单个数量小
            if (quantities.size() > 1) {
                int smallAssignments = 0;
                for (int quantity : quantities) {
                    if (quantity < 5) { // 认为小于5个为过小分配
                        smallAssignments++;
                    }
                }
                fragmentationPenalty += smallAssignments * quantities.size(); // 任务分散度惩罚
            }
        }

        // 综合成本 = 超期惩罚 * 超期权重 + 负载均衡惩罚 * 负载均衡权重 + 任务分散惩罚 * 任务分散权重
        return (loadBalancePenalty * LOAD_BALANCE_WEIGHT) ;
    }
    /**
     * 生成扰动方案
     * 根据温度不同采用不同的扰动策略
     */
    private void generateNeighbor(double temperature) {
        // 根据温度选择扰动策略
        double random = rand.nextDouble();

        // 高温时更倾向于大范围扰动
        if (temperature > INITIAL_TEMPERATURE * 0.7) {
            if (random < 0.3) {
                //System.out.println("交换");
                swapTasksBetweenWorkers();
            } else if (random < 0.6) {
               // System.out.println("分配");
                reassignTask();
            }
            else {
               // System.out.println("调整");
                adjustTaskQuantity();
            }
        }
        // 中温时平衡扰动
        else if (temperature > INITIAL_TEMPERATURE * 0.3) {
            if (random < 0.4) {
               // System.out.println("交换");
                swapTasksBetweenWorkers();
            } else if (random < 0.7) {
               // System.out.println("分配");
                reassignTask();
            }
            else {
                //System.out.println("调整");
                adjustTaskQuantity();
            }
        }
        // 低温时更倾向于小范围扰动
        else {
            if (random < 0.5) {
               // System.out.println("交换");
                swapTasksBetweenWorkers();
            }
            else {
               // System.out.println("调整");
                adjustTaskQuantity();
            }
        }
        refreshCache();
    }
    /**
     * 在两个工人之间交换任务
     */
    private void swapTasksBetweenWorkers() {
        if (workers.size() < 2) return;

        int worker1Index = rand.nextInt(workers.size());
        int worker2Index;
        do {
            worker2Index = rand.nextInt(workers.size());
        } while (worker2Index == worker1Index);

        WorkerHandle worker1 = workers.get(worker1Index);
        WorkerHandle worker2 = workers.get(worker2Index);

        if (worker1.getAssignments().isEmpty() || worker2.getAssignments().isEmpty()) return;

        int task1Index = rand.nextInt(worker1.getAssignments().size());
        int task2Index = rand.nextInt(worker2.getAssignments().size());

        TaskAssignment task1 = worker1.getAssignments().get(task1Index);
        TaskAssignment task2 = worker2.getAssignments().get(task2Index);

        // 先计算原来的任务时间
        double task1Time = worker1.calculateTaskTotalTime(task1);
        double task2Time = worker2.calculateTaskTotalTime(task2);

        // 检查工人是否能处理对方的任务，并且有足够的可用时间交换后保持非负
        if (worker1.canHandle(task2) && worker2.canHandle(task1) &&
                worker1.getAvailable() - task2Time + task1Time >= 0 &&
                worker2.getAvailable() - task1Time + task2Time >= 0) {
            // 移除任务
            worker1.getAssignments().remove(task1Index);
            worker2.getAssignments().remove(task2Index);

            // 调整工人可用时间
            worker1.setAvailable(worker1.getAvailable() + task1Time);
            worker2.setAvailable(worker2.getAvailable() + task2Time);

            // 重新分配任务
            worker1.assignTask(task2);
            worker2.assignTask(task1);

            // 减少可用时间 - 因为已经预先检查，不需要Math.max防止负数
            worker1.setAvailable(worker1.getAvailable() - task2Time);
            worker2.setAvailable(worker2.getAvailable() - task1Time);

            // 重新计算时间表
            worker1.recalculateSchedule(baseDate);
            worker2.recalculateSchedule(baseDate);

        }
    }


    /**
     * 重新分配任务给其他工人
     */
    private void reassignTask() {
        if (workers.size() < 2) return;

        int workerIndex = rand.nextInt(workers.size());
        WorkerHandle sourceWorker = workers.get(workerIndex);

        if (sourceWorker.getAssignments().isEmpty()) return;

        int taskIndex = rand.nextInt(sourceWorker.getAssignments().size());
        TaskAssignment task = sourceWorker.getAssignments().get(taskIndex);

        // 计算任务所需时间
        double taskTime = sourceWorker.calculateTaskTotalTime(task);

        // 尝试找到能处理该任务的其他工人
        List<WorkerHandle> possibleWorkers = new ArrayList<>();
        for (WorkerHandle worker : workers) {
            if (worker != sourceWorker && worker.canHandle(task) && worker.getAvailable() >= taskTime) {
                possibleWorkers.add(worker);
            }
        }

        if (!possibleWorkers.isEmpty()) {
            WorkerHandle targetWorker = possibleWorkers.get(rand.nextInt(possibleWorkers.size()));

            // 移除原任务
            sourceWorker.getAssignments().remove(taskIndex);

            // 调整源工人可用时间
            sourceWorker.setAvailable(sourceWorker.getAvailable() + taskTime);

            // 分配给新工人
            targetWorker.assignTask(task);

            // 减少目标工人可用时间
            targetWorker.setAvailable(Math.max(targetWorker.getAvailable() - taskTime, 0));

            // 重新计算时间表
            sourceWorker.recalculateSchedule(baseDate);
            targetWorker.recalculateSchedule(baseDate);

            // 无需更新缓存，因为任务总分配数量没有变化
        }
    }


    /**
     * 拆分任务数量：将一个工人的部分任务数量分配给另一个适合的工人
     */
    private void adjustTaskQuantity() {
        // 随机选择源工人
        int sourceWorkerIndex = rand.nextInt(workers.size());
        WorkerHandle sourceWorker = workers.get(sourceWorkerIndex);

        if (sourceWorker.getAssignments().isEmpty()) return;

        // 随机选择源任务
        int taskIndex = rand.nextInt(sourceWorker.getAssignments().size());
        TaskAssignment sourceTask = sourceWorker.getAssignments().get(taskIndex);
        int currentQuantity = sourceTask.getAssignedQuantity();

        // 设置任务数量调整的最小阈值和最大阈值
        final int MIN_TASK_QUANTITY = 5; // 每个工人至少保留的数量
        final int MAX_TRANSFER_QUANTITY = 100; // 最多一次转移的数量

        // 如果源任务数量不足以分割，则退出
        if (currentQuantity <= MIN_TASK_QUANTITY + 1) return;

        // 计算可转移的最大数量
        int maxTransferableQuantity = Math.min(currentQuantity - MIN_TASK_QUANTITY, MAX_TRANSFER_QUANTITY);

        // 随机确定要转移的数量
        int transferQuantity = rand.nextInt(maxTransferableQuantity) + 1;

        if(transferQuantity < MIN_TASK_QUANTITY) return;

        // 寻找可以接收该任务的其他工人
        List<WorkerHandle> eligibleWorkers = new ArrayList<>();
        for (WorkerHandle worker : workers) {
            // 跳过源工人自己
            if (worker == sourceWorker) continue;

            // 检查工人是否能处理该类型的任务
            if (!worker.canHandle(sourceTask)) continue;

            // 创建临时任务来计算所需时间
            TaskAssignment tempTask = new TaskAssignment(
                    sourceTask.getItemID(),
                    sourceTask.getOrderCode(),
                    sourceTask.getFlowOrderCode(),
                    sourceTask.getItemName(),
                    sourceTask.getItemDifficulty(),
                    sourceTask.getWorkcenterName(),
                    transferQuantity,
                    sourceTask.getPreCycle(),
                    sourceTask.getMakeCycle(),
                    sourceTask.getDeadline()
            );

            double requiredTime = worker.calculateTaskTotalTime(tempTask);

            // 检查工人是否有足够的可用时间
            if (worker.getAvailable() >= requiredTime) {
                eligibleWorkers.add(worker);
            }
        }

        // 如果没有合适的工人，则退出
        if (eligibleWorkers.isEmpty()) return;

        // 随机选择一个目标工人
        WorkerHandle targetWorker = eligibleWorkers.get(rand.nextInt(eligibleWorkers.size()));

        // 记录操作前的总零件数（用于验证）
        int beforeTotalParts = 0;
        for (WorkerHandle w : workers) {
            for (TaskAssignment t : w.getAssignments()) {
                beforeTotalParts += t.getAssignedQuantity();
            }
        }

        // 计算源任务需要减少的时间
        double oldSourceTime = sourceWorker.calculateTaskTotalTime(sourceTask);

        // 减少源工人的任务数量
        sourceTask.setAssignedQuantity(currentQuantity - transferQuantity);

        // 计算源任务现在需要的时间
        double newSourceTime = sourceWorker.calculateTaskTotalTime(sourceTask);

        // 调整源工人的可用时间
        double timeSaved = oldSourceTime - newSourceTime;
        sourceWorker.setAvailable(sourceWorker.getAvailable() + timeSaved);

        // 检查目标工人是否已经有相同的任务
        boolean taskExists = false;
        TaskAssignment existingTask = null;

        for (TaskAssignment task : targetWorker.getAssignments()) {
            if (task.getItemID().equals(sourceTask.getItemID()) &&
                    task.getOrderCode().equals(sourceTask.getOrderCode())) {
                taskExists = true;
                existingTask = task;
                break;
            }
        }

        if (taskExists) {
            // 如果目标工人已有相同任务，增加其数量
            int oldQuantity = existingTask.getAssignedQuantity();
            existingTask.setAssignedQuantity(oldQuantity + transferQuantity);
        } else {
            // 否则，创建新任务分配给目标工人
            TaskAssignment newTask = new TaskAssignment(
                    sourceTask.getItemID(),
                    sourceTask.getOrderCode(),
                    sourceTask.getFlowOrderCode(),
                    sourceTask.getItemName(),
                    sourceTask.getItemDifficulty(),
                    sourceTask.getWorkcenterName(),
                    transferQuantity,
                    sourceTask.getPreCycle(),
                    sourceTask.getMakeCycle(),
                    sourceTask.getDeadline()
            );

            targetWorker.assignTask(newTask);
        }

        // 计算目标工人需要增加的时间
        TaskAssignment tempTask = new TaskAssignment(
                sourceTask.getItemID(),
                sourceTask.getOrderCode(),
                sourceTask.getFlowOrderCode(),
                sourceTask.getItemName(),
                sourceTask.getItemDifficulty(),
                sourceTask.getWorkcenterName(),
                transferQuantity,
                sourceTask.getPreCycle(),
                sourceTask.getMakeCycle(),
                sourceTask.getDeadline()
        );

        double requiredTime = targetWorker.calculateTaskTotalTime(tempTask);

        // 减少目标工人的可用时间
        targetWorker.setAvailable(Math.max(0, targetWorker.getAvailable() - requiredTime));

        // 重新计算两个工人的时间表
        sourceWorker.recalculateSchedule(baseDate);
        targetWorker.recalculateSchedule(baseDate);

        // 刷新缓存
        refreshCache();

        // 验证操作后的总零件数
        int afterTotalParts = 0;
        for (WorkerHandle w : workers) {
            for (TaskAssignment t : w.getAssignments()) {
                afterTotalParts += t.getAssignedQuantity();
            }
        }
    }
    /**
     * 运行模拟退火算法
     */
    public void run() {
        // 初始化分配
        initialAssignment();
        System.out.println("开始");

        // 确保初始缓存正确
        refreshCache();

        // 记录初始分配的零件总数
        int initialAssignedCount = 0;
        for (WorkerHandle worker : workers) {
            for (TaskAssignment task : worker.getAssignments()) {
                initialAssignedCount += task.getAssignedQuantity();
            }
        }
        System.out.println("初始分配零件总数: " + initialAssignedCount);

        double currentTemperature = INITIAL_TEMPERATURE;
        double bestCost = calculateCost(workers);
        List<WorkerHandle> bestSolution = deepCopyWorkers(workers);

        // 创建最佳解的缓存
        Map<String, Integer> bestSolutionCache = new HashMap<>(assignedQuantityCache);

        // 保存当前解
        List<WorkerHandle> currentSolution = deepCopyWorkers(workers);
        double currentCost = bestCost;
        Map<String, Integer> currentCache = new HashMap<>(assignedQuantityCache);
        System.out.println(bestCost);
        while (currentTemperature > MIN_TEMPERATURE) {
            int res=0;
            for (int i = 0; i < MAX_ITERATIONS_PER_TEMP; i++) {
                // 保存当前状态和缓存
                res++;
                if(res>NO_IMPROVEMENT_LIMIT) break;
                generateNeighbor(currentTemperature);
                double newCost = calculateCost(workers);
                //System.out.println("newCost: "+newCost);
                double acceptanceProbability;
                if (newCost < currentCost) {
                    acceptanceProbability = 1.0; // 如果新解更好，总是接受
                } else {
                    // 根据温度和成本差异计算接受概率
                    acceptanceProbability = Math.exp((currentCost - newCost) / currentTemperature);
                }
                // 根据概率决定是否接受新解
                if (acceptanceProbability > rand.nextDouble()) {
                    // 接受新解
                    currentCost = newCost;
                    currentSolution = deepCopyWorkers(workers);
                    currentCache = new HashMap<>(assignedQuantityCache);

                    // 更新最优解
                    if (newCost < bestCost) {
                        bestCost = newCost;
                        bestSolution = deepCopyWorkers(workers);
                        bestSolutionCache = new HashMap<>(assignedQuantityCache);
                        res = 0;
                    }
                } else {
                    // 拒绝新解，恢复到当前解
                    workers = deepCopyWorkers(currentSolution);
                    assignedQuantityCache = new HashMap<>(currentCache);
                }
            }
            // 降温
            currentTemperature *= COOLING_RATE;
        }

        // 应用最佳解和对应缓存
        workers = bestSolution;
        System.out.print(calculateCost(workers));
        int number=0;
        for (int i = 0; i < workers.size(); i++) {
            WorkerHandle worker = workers.get(i);
            System.out.println("\n工人: " + worker.getEmployeeName() +"能力系数："+worker.getCapacityCodfficient()+"劳动效率："+worker.getEfficiencyCodfficient()+
                    ", 剩余可用时间: " + String.format("%.2f", worker.getAvailable()) + " 小时");
            List<TaskAssignment> taskAssignments = worker.getAssignments();
            if (taskAssignments.isEmpty()) {
                System.out.println("没有分配任务");
            } else {
                for (int j = 0; j < taskAssignments.size(); j++) {
                    TaskAssignment t = taskAssignments.get(j);
//                    System.out.println("  任务 #" + (j+1) + ": " + t.getItemID() + "_" + t.getOrderCode() +
//                            ", 数量: " + t.getAssignedQuantity() +
//                            ", 难度: " + t.getItemDifficulty());
                    number+=t.getAssignedQuantity();
                }
            }
        }
        System.out.println("初始分配零件总数: " + initialAssignedCount);
        System.out.println("最终分配零件总数: " + number);
        if (initialAssignedCount != number) {
            System.out.println("警告: 分配零件总数发生变化！差异: " + (initialAssignedCount - number));
        }
        assignedQuantityCache = bestSolutionCache;
    }
    /**
     * 深拷贝工人列表
     */
    private List<WorkerHandle> deepCopyWorkers(List<WorkerHandle> original) {
        List<WorkerHandle> copy = new ArrayList<>();
        for (WorkerHandle worker : original) {
            WorkerHandle workerCopy = new WorkerHandle();
            // 复制工人属性
            workerCopy.setId(worker.getId());
            workerCopy.setEmployeeName(worker.getEmployeeName());
            workerCopy.setEmployeeNo(worker.getEmployeeNo());
            workerCopy.setMdsWorkerGroupName(worker.getMdsWorkerGroupName());
            workerCopy.setCapacityCodfficient(worker.getCapacityCodfficient());
            workerCopy.setEfficiencyCodfficient(worker.getEfficiencyCodfficient());
            workerCopy.setAvailable(worker.getAvailable());
            workerCopy.setAccumulatedWorkHours(worker.getAccumulatedWorkHours());
            // 复制工作日历对象
            workerCopy.setWorkCalendar(worker.getWorkCalendar());
            // 深拷贝任务分配
            List<TaskAssignment> assignmentsCopy = new ArrayList<>();
            for (TaskAssignment task : worker.getAssignments()) {
                TaskAssignment taskCopy = new TaskAssignment(
                        task.getItemID(),
                        task.getOrderCode(),
                        task.getFlowOrderCode(),
                        task.getItemName(),
                        task.getItemDifficulty(),
                        task.getWorkcenterName(),
                        task.getAssignedQuantity(),
                        task.getPreCycle(),
                        task.getMakeCycle(),
                        task.getDeadline()
                );
                taskCopy.setStartTime(task.getStartTime());
                taskCopy.setEndTime(task.getEndTime());
                assignmentsCopy.add(taskCopy);
            }
            workerCopy.setAssignments(assignmentsCopy);
            copy.add(workerCopy);
        }
        return copy;
    }
}
